package bluetooth;


import java.awt.Robot;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;

import javax.microedition.io.StreamConnection;

import util.Util;

import client.ClientConnectable;
import exception.NFCException;


public class BluetoothConnectedThread extends Thread {
	
	public static final boolean D = false;

	private static final String HEADER = "$$";

	private static final String FOOTER = "-|%";

	private StreamConnection mConnection;
	
	private InputStream inputStream;
	private OutputStream outputStream;

	private final ClientConnectable client;

	public BluetoothConnectedThread(StreamConnection connection, ClientConnectable client)  {
		mConnection = connection;
		this.client = client;
		
		try {
			inputStream = mConnection.openInputStream();
			outputStream = mConnection.openOutputStream();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		while (true) {
			try {
				byte[] auxToConcatenate =  new byte[0], dataUtil =  new byte[0], deusnosacuda =  new byte[0];
				byte[] bytes = new byte[8*1024];
				int retorno = -1;
				boolean iniciouConserto = false;
				while (retorno == -1){
					Thread.sleep(300);
					retorno = inputStream.read(bytes);
					if(retorno != -1){
						String arrayEmString = (new String(bytes)).trim();
						if(bytes[0] == -1 &&  bytes[1] == 0 &&  bytes[2] == 0 &&  bytes[3] == 0)
							return;
						int headerLength = 8; int footerLengh = FOOTER.length();
						int indexInicioFooter =  arrayEmString.indexOf(FOOTER);
						int fimDaDataUtil = -1; boolean erroNoFooter = true;
						
						String out = "";
						if(indexInicioFooter != -1){//nao tem footer, mensagem incompleta
							byte[] footerBytes = Arrays.copyOfRange(bytes, indexInicioFooter,indexInicioFooter + 3);
							out = " ### Footer= " + new String(footerBytes);
							fimDaDataUtil = indexInicioFooter;
						}else{
							erroNoFooter = false;
							fimDaDataUtil = bytes.length;
						}
						byte[] headerBytes = Arrays.copyOfRange(bytes, 0, headerLength);
						try {
							dataUtil =  Arrays.copyOfRange(bytes, headerLength, fimDaDataUtil);
						} catch (Exception e) {
						}
						out = "############# Header= " + new String(headerBytes) + out; 
						
						String header = new String(headerBytes);
						if(header.charAt(0) == '$' && header.charAt(1) == '$' && header.charAt(6) == '$' && header.charAt(7) == '$'){
							header = header.substring(2, 6);
							int numBytesEscritos = Integer.parseInt(header);
							int numBytesLidos = -1;
							numBytesLidos = retorno - (erroNoFooter?(headerLength + footerLengh):(headerLength));
							
							if(numBytesLidos < numBytesEscritos) {
								auxToConcatenate = dataUtil.clone();								
								retorno = -1;
								if(D) System.err.println("!!! Iniciou o conserto");
								iniciouConserto = true;
							} else if(numBytesLidos > numBytesEscritos) {
								bytes = Arrays.copyOfRange(dataUtil, 0, numBytesEscritos);															
								retorno = numBytesEscritos;
							} else  if(numBytesLidos == numBytesEscritos) {
								bytes = dataUtil.clone();
								retorno = numBytesLidos;
							}
						}else{//Veio a segunda parte quebrada
							if(iniciouConserto){
								if(erroNoFooter){
									// pegar ate o inicio do footer e armazena o resto que sobrar
									bytes = Util.concat(auxToConcatenate, dataUtil);
									String auxteste = new String(dataUtil);
									if(D) System.err.println("!!! Finalizou o conserto.  Com DataUtil");
								}else{//pegar ate o fim
									bytes = Util.concat(auxToConcatenate, bytes);
									retorno = bytes.length;
									if(D) System.err.println("!!! Finalizou o conserto.  Com bytes");
								}
								iniciouConserto = false;
							}else{
								try {
									//bytes = Util.concat(auxToConcatenate, bytes);
									if(D) System.out.print("!!%%%%%%! Erro no pacote... ");
									String auxteste = new String(bytes);
									boolean containsHeader = auxteste.contains(HEADER);
									boolean contemCabecalho = false; 
									if(containsHeader){
										int indexOf = auxteste.indexOf(HEADER);
										String num = auxteste.substring( indexOf + 2,  indexOf + 6);
										int numBytesEscritos = Integer.parseInt(num);
										
										int arraySize = (numBytesEscritos - ( bytes.length - indexOf)) + footerLengh;
										
										byte[] primeiraParte = Arrays.copyOfRange(bytes, indexOf + headerLength, bytes.length);
										if(D) System.out.print("[ Faltando= " + (numBytesEscritos -  primeiraParte.length) );
										String teste1 = new String(primeiraParte);
										
										byte[] segundaParte = new byte[0];
										int faltando = arraySize; int retorno2 = -1;
										while(segundaParte.length < faltando){
											byte[] auxiliar = new byte[arraySize];
											while (retorno2 == -1){
												retorno2 = inputStream.read(auxiliar);
											}
											segundaParte =  Util.concat(segundaParte, Arrays.copyOfRange(auxiliar,0, retorno2));
											arraySize = faltando - segundaParte.length;
											if(arraySize <= 0){
												break;
											}
											
										}
										int segundaParteLength = segundaParte.length;
										String teste2 = new String(segundaParte);
										if(retorno2 != -1){
											bytes =  Util.concat(primeiraParte, segundaParte);
										}else{
											System.out.println("Nao leu nada");
										}
										if(D) System.out.print("    bytes.lengh= " +bytes.length + " ]");
										if(D) System.out.println("....Corrigido");
										
									}
									else
										if(D) System.err.println(".. Descartado");
								} catch (NumberFormatException e) {
									if(D) System.err.println("Erro! Descartado");
								}
								//System.out.println(arrayEmString);
							}
						}
					}
				}
				if(retorno != -1) if(D) System.out.println("BytesLidos= " + retorno );
				try {
					System.out.println("### [BLU] Mensagem recebida: " + new String(bytes).substring(0,4));
				} catch (Exception e) {
					System.out.println("### [BLU] Mensagem recebida: ....");
				}
				
				sendData(bytes);
			} catch (IOException e) {
				System.err.println("Exception during reading bluetooth");
				e.printStackTrace();
				break;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
	}
		}
	
	public void sendData(final byte[] bytes) {
        Thread robo = new Thread(new Runnable() {
            @Override
            public void run() {
            	//System.err.println(">>Robo Executando para enviar bytes= " + bytes.length);
            	client.receiveData(bytes);
            	//System.out.println(">>>> "+ new String(bytes));
            }
        });
        robo.setPriority(MAX_PRIORITY);
        //System.err.println("Criado robo para enviar bytes= " + bytes.length);
        robo.start();
	}
	
	
	public void cancel(){
		try {
			outputStream.flush();
			outputStream.close();			
		} catch (IOException e) {
			System.err.println("Exception during closing outputStream bluetooth");
		}
		
		try {
			inputStream.close();
		} catch (IOException e) {
			System.err.println("Exception during closing inputStream bluetooth");
		}
	}

	

	public void write(byte[] buffer) throws NFCException {
		try {
			outputStream.write(buffer);
			outputStream.flush();
		} catch (IOException e) {
			System.err.println("Exception during write bluetooth");
			throw new NFCException("Error during bluetooth writing.. " + e.getMessage());
		}
	}
	
	
}
